#include "SQLUpdateSetItem.h"

#include "../SQLExpr.h"
#include "../SQLName.h"
#include "../expr/SQLIdentifierExpr.h"
#include "../expr/SQLPropertyExpr.h"
#include "../../visitor/SQLASTVisitor.h"

#include "../../../Exception/FastsqlException.h"
#include "../../parser/IOException.h"
#include "../../../utils/instanceof.h"

SQLUpdateSetItem::SQLUpdateSetItem()
{
}

SQLExpr_ptr SQLUpdateSetItem::getColumn()
{
  return column;
}

void SQLUpdateSetItem::cloneTo(SQLUpdateSetItem *x)
{
  if (column != NULL)
  {
    x->column = std::dynamic_pointer_cast<SQLExpr>(column->clone());
    x->column->setParent(SharedObject(SQLUpdateSetItem));
  }
  if (value != NULL)
  {
    x->value = std::dynamic_pointer_cast<SQLExpr>(value->clone());
    x->value->setParent(SharedObject(SQLUpdateSetItem));
  }
}

SQLObject_ptr SQLUpdateSetItem::clone()
{
  SQLObject_ptr clone_tmp = SQLUpdateSetItem_ptr(new SQLUpdateSetItem());
  SQLUpdateSetItem_ptr x = std::dynamic_pointer_cast<SQLUpdateSetItem>(clone_tmp);
  // SQLUpdateSetItem *x = new SQLUpdateSetItem();
  cloneTo(x.get());
  return x;
}

void SQLUpdateSetItem::setColumn(SQLExpr_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLUpdateSetItem));
  }
  this->column = x;
}

SQLExpr_ptr SQLUpdateSetItem::getValue()
{
  return value;
}

void SQLUpdateSetItem::setValue(SQLExpr_ptr value)
{
  if (value != NULL)
  {
    value->setParent(SharedObject(SQLUpdateSetItem));
  }
  this->value = value;
}

void SQLUpdateSetItem::output(std::stringstream *  buf)
{
  try
  {
    column->output(buf);
    (*buf)<<" = ";
    value->output(buf);
  }
  catch (IOException ex)
  {
    // throw new FastsqlException("output error", ex);
    throw new FastsqlException(make_string_ptr("output error"));
  }
}

void SQLUpdateSetItem::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLUpdateSetItem)))
  {
    if (column != NULL)
    {
      column->accept(visitor);
    }

    if (value != NULL)
    {
      value->accept(visitor);
    }
  }

  visitor->endVisit(SharedObject(SQLUpdateSetItem));
}

BOOL_ptr SQLUpdateSetItem::columnMatch(string_ptr  column)
{
  if (instanceof <SQLExpr, SQLIdentifierExpr>(this->column))
  {
    return (std::dynamic_pointer_cast<SQLIdentifierExpr>(this->column))->nameEquals((column));
  }
  else if (instanceof <SQLExpr, SQLPropertyExpr>(this->column))
  {
    (std::dynamic_pointer_cast<SQLPropertyExpr>(this->column))->nameEquals((column));
  }
  return BOOL::FALSE;
}

BOOL_ptr SQLUpdateSetItem::columnMatch(long columnHash)
{
  if (instanceof <SQLExpr, SQLName>(this->column))
  {
    return ((std::dynamic_pointer_cast<SQLName>(this->column))->nameHashCode64() == columnHash)?BOOL::TRUE:BOOL::FALSE;
  }

  return BOOL::FALSE;
}

BOOL_ptr SQLUpdateSetItem::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  if (expr == this->column)
  {
    this->setColumn(target);
    return BOOL::TRUE;
  }

  if (expr == this->value)
  {
    setValue(target);
    return BOOL::TRUE;
  }
  return BOOL::FALSE;
}

bool SQLUpdateSetItem::equals(Object_ptr o)
{
  if (this == o.get())
  {
    return true;
  }
  if (o == NULL || getClass() != o->getClass())
  {
    return false;
  }

  SQLUpdateSetItem_ptr that = std::dynamic_pointer_cast<SQLUpdateSetItem>(o);

  if (column != NULL ? !column->equals(that->column) : that->column != NULL)
  {
    return false;
  }
  return value != NULL ? value->equals(that->value) : that->value == NULL;
}

int SQLUpdateSetItem::hashCode()
{
  int result = column != NULL ? column->hashCode() : 0;
  result = 31 * result + (value != NULL ? value->hashCode() : 0);
  return result;
}
